# vim: tabstop=4 shiftwidth=4 softtabstop=4

"""
base exception handling, including decorator for re-raising
exceptions. SHOULD include dedicated exception logging.
"""

import logging


class Error(Exception):
    message = "An unknown exception has occurred. please contact us"
    def __init__(self, message=None,**kwargs):
        if not message:
            message = self.message % kwargs
        else:
            self.message = message
        super(Error, self).__init__(message)


class VolumeExists(Error):pass

class VolumeNotExists(Error):pass

class VolumeStatusShouldBeA(Error):
    message = "Volume status must be available"

class VolumeStatusShouldBeI(Error):
    message = "Volume status must be in-used,have you attached this volume yet?"

class VolumeLocationMissing(Error):
    message = "for iscsi type, volume location should be provided, now is missing"
class VolumeTooSmall(Error):
    message = "Volume size is too small"
class VolumeTooLarge(Error):
    message = "Volume size is too Large"
class VolumeExtendFail(Error):
    message = "Extend Volume fail"
class VolumeServerIsFull(Error):
    message = "Volume server needs enlarge"

class VolumeExportFail(Error):
    message = "Export %(volume_name)s failed"

class FetchImageError(Error):
    message = "Open image %(image_loc)s and set a new uuid failed."

class VolumeIsBusy(Error):
    message = "deleting volume %(volume_name)s that has snapshot"

class _NoopContextManager(object):
    def __enter__(self):
        pass

    def __exit__(self, exc_type, exc_val, exc_tb):
        pass

class ProcessExecutionError(IOError):
    def __init__(self, stdout=None, stderr=None, exit_code=None, cmd=None,
                 description=None):

        self.exit_code = exit_code
        self.stderr = stderr
        self.stdout = stdout
        self.cmd = cmd
        self.description = description

        if description is None:
            description = "Unexpected error while running command."
        if exit_code is None:
            exit_code = '-'
        message = "%s\nCommand: %s\nExit returncode: %s\nStdout: %r\nStderr: %r" \
                  % (description, cmd, exit_code, stdout, stderr)
        IOError.__init__(self, message)




class ApiError(Error):
    def __init__(self, message='Unknown', code='Unknown'):
        self.message = message
        self.returncode = code
        super(ApiError, self).__init__('%s: %s' % (code, message))


class NotFound(Error):
    pass


class UnknownScheme(Error):

    msg = "Unknown scheme '%s' found in URI"

    def __init__(self, scheme):
        msg = self.__class__.msg % scheme
        super(UnknownScheme, self).__init__(msg)


class BadStoreUri(Error):

    msg = "The Store URI %s was malformed. Reason: %s"

    def __init__(self, uri, reason):
        msg = self.__class__.msg % (uri, reason)
        super(BadStoreUri, self).__init__(msg)


class Duplicate(Error):
    pass


class AuthorizationFailure(Error):
    pass


class NotAuthorized(Error):
    pass


class NotEmpty(Error):
    pass


class Invalid(Error):
    pass


class RedirectException(Error):
    def __init__(self, url):
        self.url = url


class BadInputError(Exception):
    """Error resulting from a client sending bad input to a server"""
    pass


class MissingArgumentError(Error):
    pass


class DatabaseMigrationError(Error):
    pass


class ClientConnectionError(Exception):
    """Error resulting from a client connecting to a server"""
    pass


def wrap_exception(f):
    def _wrap(*args, **kw):
        try:
            return f(*args, **kw)
        except Exception, e:
            if not isinstance(e, Error):
                #exc_type, exc_value, exc_traceback = sys.exc_info()
                logging.exception('Uncaught exception')
                #logging.error(traceback.extract_stack(exc_traceback))
                raise Error("%s" % e)
            raise
    _wrap.func_name = f.func_name
    return _wrap

class ImageNotExist(NotFound):
    message = "The image %(image_id)s is not exist."

class ImageInvalid(Error):
    message = "The image %(image_id) of uuid opened can't match the uuid recorded"

class InstanceLockFailed(Error):
    pass

class InstanceNotRunning(Error):
    message = "Instance %(name)s is not running"

class InstanceExists(Duplicate):
    message = "Instance %(name)s already exists."

class InstanceProcessorInvalid(Error):
    message = "Instance cpu core number is twice bigger than host(%(cpu_core)s)."

class InstanceMemoryInvalid(Error):
    message = "There is not enough memory(%(memory_exist)sMB) for instance(%(memory_required)sMB)."

class InstanceRegisterFailure(Error):
    message = "Register instance failed."

class InstanceUnregisterFailure(Error):
    pass

class InstanceCreateFailure(Error):
    message = "Instance %(name)s created failed."

class InstanceNotFound(NotFound):
    message = "Instance %(instance_id)s could not be found."

class InstanceNotFoundInHost(NotFound):
    message = "Instance %(name)s could not be found in host %(host)s."

class InstanceNotFoundInDB(NotFound):
    message = "Instance %(name)s could not be found in DB."

class InstanceAttachFailure(Error):
    message = "Attach image to instance failed."

class InstanceStartFailure(Error):
    message = "Start instance %(name)s failed."

class InstanceDestroyFailure(Error):
    message = "Destroy instance %(name)s failed."

class InstanceShutdownRequired(Error):
    message = "The instance %(name)s should be in state Running, Paused, Stuck for shutdown."

class InstanceShutdownFailure(Error):
    message = "Shutdown instance %(name)s failed."

class InstanceRebootFailure(Error):
    message = "Reboot instance %(name)s failed."

class InstancePauseRequired(Error):
    message = "The instance %(name)s should be in state Running for pause."

class InstancePauseFailure(Error):
    message = "Pause instance %(name)s failed."

class InstanceUnpauseRequired(Error):
    message = "The instance %(name)s should be in state Paused for unpause."

class InstanceUnpauseFailure(Error):
    message = "Unpause instance %(name)s failed."

class InstanceHibernateRequired(Error):
    message = "The instance %(name)s should be in state Running for hibernate."

class InstanceHibernateFailure(Error):
    message = "Hibernate instance %(name)s failed."

class InstanceResizeInvalid(Error):
    message = "The instance %(name)s can't be resized to %(cpu)s cpu and %(memory)s memory, there are no more resources left in this host"

class InstanceResizeRequired(Error):
    message = "The instance %(name)s should be in state Shutdown for resize."

class InstanceResizeFailure(Error):
    message = "Resize instance %(name)s failed."

class SnapshotNotSupport(Error):
    message = "raw type driver are not supported to do snapshot in current version."

class SnapshotNotFound(NotFound):
    message = "Snapshot %(snapshot_id)s could not be found."

class SnapshotTakeRequired(Error):
    message = "The instance %(name)s should be in state PoweredOff, Saved, Running or Paused for snapshot."

class SnapshotTakeFailure(Error):
    message = "Snapshot instance %(name)s failed."

class SnapshotTooMuch(Error):
    message = "you can't snapshot this instance before you remove the snapshots."

class SnapshotRestoreInvalid(Error):
    message = "The instance %(name)s can not be restored to snapshot when it is Running."

class SnapshotRestoreDirectParentInvalid(Error):
    message = "The instance %(name)s can not be restored to snapshot %(snapshot_id)s since this snapshot has children."

class SnapshotResotreFailure(Error):
    message = "Restore snapshot %(snapshot_id)s for instance %(name)s failed."

class SnapshotDeleteInvalid(Error):
    message = "Delete snapshot %(snapshot_id)s for instance %(name)s invalid since this snapshot has multi-children."

class SnapshotDeleteFailure(Error):
    message = "Delete snapshot %(snapshot_id)s for instance %(name)s failed."

class BlockMigrationPortRequired(NotFound):
    message = "There is not block migration port in host %(host)s."

class BlockMigrationReceiveFailure(Error):
    message = "Block migration receive images file of instance %(name)s failed."

class BlockMigrationSendFailure(Error):
    message = "Block migration send images file of instance %(name)s failed."

class BlockMigrationRequired(Error):
    message = "Block migration of instance %(name)s should be in state Shutdown."

class BlockMigrationMediumFailure(Error):
    message = "Block migration open primary medium for instance %(name)s failed."

class BlockMigrationOpenMachineFailure(Error):
    message = "Block migration open machine for instance %(name)s failed."

class BlockMigrationRegisterFailure(Error):
    message = "Block migration register instance %(name)s failed."

class BlockMigrationAttachFailure(Error):
    message = "Block migration attach image to instance %(name)s failed."

class TeleportPortRequired(NotFound):
    message = "Teleport port is missing in host %(host)s."

class TeleportInstanceStateRequired(Error):
    message = "The instance %(name)s should be in Running or Pause for teleport."

class TeleportShareStorageRequired(Error):
    message = "Share storage is required for teleport of instance %(name)s."

class TeleportMediumFailure(Error):
    message = "Pre teleport open primary medium for instance %(name)s failed."

class TeleportRegisterFailure(Error):
    message = "Pre teleport register instance %(name)s failed."

class TeleportAttachFailure(Error):
    message = "Pre teleport attach images to instance %(name)s failed."

class TeleportingFailure(Error):
    message = "Teleport instance %(name)s from source host %(src_host)s to destination host %(dest_host)s failed."

class ServiceNotFound(NotFound):
    def __init__(self,host=None,message=None,**kwargs):
        self.host = host
        if not message:
            self.message = "Service %s could not be found." % host
        super(ServiceNotFound,self).__init__(message=message,**kwargs)


class ServiceRequireRunningDuringMigration(NotFound):
    message = "Agent Service is not running on %(host), live migration checking is failed"

class EthNotFound(NotFound):pass

class IscsiTargetNotFound(NotFound):
    message = "No more iscsi target found for this host"

class TransportImageError(IOError):
    def __init__(self, size=None, src=None, dest=None, readed=None, description=None):
        if description is None:
            description = "Unexpected error while transport image."
        message = "%s\nTransport Image: %s\nSize: %s\ntransported at: %s\nform: %s" \
                  % (description, dest, size, readed, src)
        IOError.__init__(self, message)

class InstanceMediumNotFound(NotFound):
    message = "Instance medium with uuid %(uuid)s is not in database."

class InstanceMediumNotExist(Error):
    message = "Instance medium with location %(location)s is not exist."

class FixedIpNoMore(NotFound):
    message = "There is no more fixed ips of instance %(instance_id)s"

class FixedIpNoMoreForNetwork(NotFound):
    message = "There is no more fixed ips of network"

class FixedIpNotFound(NotFound):
    message = "There is no fixed ip %(fixed_ip)s of %(instance_id)s exist."

class NetworkKillFailure(Error):
    message = "Kill the dnsmasq of file %(pid_file)s failed."

class NetworkInitFailure(Error):
    message = "Exception while init network ,may be network_ref is none."

class FloatingIpNotFound(NotFound):
    message = "There is no floating ip %(floating_ip)s exist."

class FloatingIpNoMore(NotFound):
    message = "There is no more floating ips."

class SecurityGroupNotFound(NotFound):
    message = "There is no security group name as %(name)s."

class DiskNotFound(NotFound):
    message = "There is no disk name as %(name)s."

class InvalidDevicePath(Invalid):
    message = "The supplied device path (%(path)s) is invalid."

class InvalidSharedStorageDeployment(Invalid):
    message = "storage %(name)s(%(path)s) is Invalid shared storage, needs shared storage deployment,please contact to administrator"

class InvalidSharedStorage(Invalid):
    message = "shared storage path or username(password) is Invalid"

class InvalidMigrateStorage(Invalid):
    message = "shared storage path %(path)s is Invalid"

class InvalidMigrateNetwork(Invalid):
    message = "shared network %(name)s is Invalid"


class InvalidMigrateNetworkFilter(Invalid):
    message = "shared network filter %(name)s is Invalid"


class DBError(Error):
    """Wraps an implementation specific exception."""
    def __init__(self, inner_exception=None):
        self.inner_exception = inner_exception
        super(DBError, self).__init__(str(inner_exception))

def wrap_db_error(f):
    def _wrap(*args, **kwargs):
        try:
            return f(*args, **kwargs)
        except Exception, e:
            logging.exception('DB exception wrapped.')
            raise DBError(e)
    _wrap.func_name = f.func_name
    return _wrap

class FixedIpAssociateFailure(DBError):
    message = "DB exception while associate fixed ip for instance %(name)s."

class FixedIpDeallocateFailure(DBError):
    message = "DB exception while deallocate fixed ips for instance %(name)s."

class FloatingIpAssociateFailure(DBError):
    message = "DB exception while associate floating ip %(floating_ip)s to fixed ip %(fixed_ip)s."

class FloatingIpDisassociateFailure(DBError):
    message = "DB exception while disaccociate floating ip %(floating_ip)s."


class InvalidHypervisorType(Invalid):
    message = "The supplied hypervisor type of is invalid."
class InvalidCPUInfo(Invalid):
    message = "The cpu info is invalid, reason is %(reason)"

class DestinationHypervisorTooOld(Invalid):
    message = "The instance requires a newer hypervisor version than has been provided."

class LiveMigrationFailed(Error):
    message = "Live migration is failed,please see the log for detail."


class ISONotFound(Error):
    message = "could not found the given iso."

class InstanceIsRunning(Error):
    message = "Instance should not be running"

class TaskShouldBeLinkSyncCall(Error):
    message = "task should be decorated by link_sync_call"


class storageisbusy(Error):
    message = "storage is busy"


class notallowresizewithsnapshot(Error):
    message = "do not allow do resize with snapshots"


def cannotsnapshotwithraw():
    message = "can not snapshot with format raw"

class FixedIpNoMoreForInstance(NotFound):
    message = "There is no more fixed ips for instance"